Skip to content

fix(presets): validate required manifest mappings - #3898

Merged
mnriem merged 1 commit into
github:mainfrom
marcelsafin:fix/preset-required-sections
Jul 31, 2026
Merged

fix(presets): validate required manifest mappings#3898
mnriem merged 1 commit into
github:mainfrom
marcelsafin:fix/preset-required-sections

Conversation

@marcelsafin

Copy link
Copy Markdown
Contributor

Summary

  • require the preset, requires, and provides manifest sections to be mappings
  • raise PresetValidationError instead of leaking raw type errors from nested access
  • cover invalid section shapes with regression tests

Testing

  • uvx ruff@0.15.0 check src tests
  • .venv/bin/pytest tests/test_presets.py -q (517 passed)
  • .venv/bin/pytest -q (6114 passed, 176 skipped)

AI disclosure

GitHub Copilot helped identify the missing shape guards and review the implementation. I reproduced the failures and validated the final change with targeted and full test suites.

Assisted-by: GitHub Copilot (model: GPT-5.6 Sol, autonomous)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings July 31, 2026 08:27
@marcelsafin
marcelsafin requested a review from mnriem as a code owner July 31, 2026 08:27

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds shape validation for required preset manifest sections, preventing raw nested-access type errors.

Changes:

  • Validate preset, requires, and provides as mappings.
  • Add regression coverage for null, list, and scalar values.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
src/specify_cli/presets/__init__.py Adds required-section mapping guards.
tests/test_presets.py Tests invalid required-section shapes.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review details

  • Files reviewed: 2/2 changed files
  • Comments generated: 0 new
  • Review effort level: Balanced

@mnriem
mnriem merged commit 400ad01 into github:main Jul 31, 2026
14 checks passed
@mnriem

mnriem commented Jul 31, 2026

Copy link
Copy Markdown
Collaborator

Thank you!

mnriem pushed a commit that referenced this pull request Aug 3, 2026
…3943)

* fix(manifests): reject non-string metadata instead of crashing on it

`ExtensionManifest` and `PresetManifest` checked only key PRESENCE for
`id`/`name`/`version`/`description`, then fed the values straight to
`re.match()` and `packaging.Version()`. Both raise a bare `TypeError` on a
non-string, which is neither `ValidationError` nor `PresetValidationError`,
so it escaped every caller that already handles a malformed manifest.

YAML makes this an easy authoring slip rather than a contrived one: an
unquoted `version: 1.0` parses as a float and `id: 2` as an int.

The user-visible symptom is the one the in-tree comment above the section
guards was written to prevent (#3898 for presets, and its extension twin):
`list_installed()` degrades a bad manifest to "⚠️ Corrupted extension" but
catches only the domain error, so a single bad manifest made
`specify extension list` / `specify preset list` exit 1 with a raw
traceback and *no output at all* — hiding every healthy extension/preset
too, not just the broken one.

Also unguarded on the same path:
- extension `provides.commands[].name` → `TypeError` from the command-name
  pattern match. The sibling `file` field was already safe, since
  `relative_extension_path_violation()` rejects a non-string.
- preset `provides.templates[].name`/`.file` → `TypeError` from `re.match`
  and `os.path.normpath` respectively.

The third manifest twin, `IntegrationDescriptor`, is already hardened: it
type-checks the same four fields and catches `TypeError` alongside
`InvalidVersion`. This brings the other two in line with it.

Tests: 68 added across both suites, covering each field against float, int,
None, list, dict, and bool, plus an end-to-end guard per manifest type
asserting a healthy entry still lists while the bad one degrades. All 68
fail with the source change reverted.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants